[AD] Scalaアプリケーションの開発・保守は合同会社ミルクソフトにお任せください
この記事ではcase class
について解説します。
case classは不変なデータを表現する
case class
は不変なデータを表現するための便利な機能です。
少量のコードで簡単に不変なデータを扱うことができます。
case classを定義する
case class
は、以下のようにcase
キーワードを先頭に付けてクラスを宣言することで定義できます。
case class Owner(name: String) case class Book(title: String, owner: Owner)
case class
は通常のクラスと比較して簡単にインスタンスを作成できます。
通常のクラスはnew
キーワードをつけてインスタンスを生成しますが、case class
はインスタンスを作成する際にnew
キーワードをつける必要がありません。
また、インスタンスを作成する際に指定したパラメーターは、「不変なpublicメンバー」になります。
以下のようにインスタンスを作成する際に指定したパラメーターへクラスの外からアクセスすることができます。
val owner = Owner("Taro") println(owner.name)
実行結果は、以下のようになります。
Taro
case classを比較する
次にcase class
のインスタンスを比較する方法を説明します。
case class
は通常のクラスと比較して簡単にインスタンスの比較ができます。
case class
のインスタンスは、==
を使用して比較します。
では、「case classを定義する」で定義したBook
とOwner
を比較してみます。
以下のように2つのBook
を比較する関数を定義します。
def compare(book1: Book, book2: Book): Unit = if(book1 == book2) println("same") else println("not same")
定義した関数を実行してみます。
compare(Book("Hello World!", Owner("Taro")), Book("Hello World!", Owner("Taro")))
インスタンスの参照先が違っていても、構造が同じであれば同じものと判定されます。
same
次にtitle
は同じでOwner
が違うインスタンスを指定して関数を呼び出してみます。
compare(Book("Hello World!", Owner("Taro")), Book("Hello World!", Owner("Hanako")))
結果は以下の通り、違うものと判断されます。
not same
case classのインスタンスを文字列に変換する
Scalaのすべてのクラスは、Any
クラスの子クラスです。
そのため、case class
でもAny
クラスのtoString
メソッドを使用してインスタンスを文字列で表現することができます。
通常のクラスのtoString
メソッドは、以下のようなハッシュ値がついた文字列を返しますが、case class
のtoString
メソッドは、インスタンスの内容が理解できる文字列を返します。
Book@20ed0575
先ほどのBook
クラスのインスタンスに対してtoString
を呼び出してみます。
val book = Book("Hello World!", Owner("Taro")) println(book.toString())
case class
のtoString
は、人がインスタンスの内容を理解できる形式の文字列に変換してくれます。
Book(Hello World!,Owner(Taro))
case classをコピーする
case class
のインスタンスをコピーする方法を説明します。
case class
を使用すると元のインスタンスをコピーして、簡単に別のインスタンスを作成することができます。
以下のBook
クラスのインスタンスをコピーしてみます。
val book1 = Book("Hello World!", Owner("Taro"))
case class
のインスタンスは、copy
メソッドを使用してコピーすることができます。
以下の例では、「book2」は「book1」と同じ内容になります。
val book2 = book1.copy() println(book1.toString()) println(book2.toString())
結果は、以下のとおり「book1」と「book2」は同じことがわかります。
Book(Hello World!,Owner(Taro)) Book(Hello World!,Owner(Taro))
また、コピーする際にインスタンスの一部のみを変更することができます。
以下の例では、先ほどの「book1」の「owner」を変更しています。
val book3 = book1.copy(owner = Owner("Hanako")) println(book3.toString())
結果は以下の通り、「book3」の「title」は「book1」と同じですが「owner」が違うことがわかります。
Book(Hello World!,Owner(Hanako))
copy
メソッドはcase class
に定義したメソッドの戻り値を作成するためによく利用されます。
以下の例では、changeOwner
メソッドでowner
を変更したインスタンスを返しています。
インスタンスのメンバーの値をメソッド内で変更するのではなく、インスタンスのコピーを返すことでメソッドの復帰値のインスタンスは不変であることが保証されます。
case class Book(title: String, owner: Owner): def changeOwner(newOwner: Owner): Book = copy(owner = newOwner)
「book1」に対してchangeOwner
を呼び出してみます。
val book4 = book1.changeOwner(Owner("Hanako")) println(book4.toString())
結果は以下の通り、「book4」の「title」は「book1」と同じですが「owner」が違うことがわかります。
Book(Hello World!,Owner(Hanako))
case classをパターンマッチで利用する
最後にcase class
でパターンマッチをする方法を説明します。
以下で定義したBook
クラスのインスタンスから「title」と「owner」の「name」を取り出してみます。
val book = Book("Hello World!", Owner("Taro"))
以下のようにパターンマッチを利用して「title」と「owner」の「name」を取り出すことができます。
val Book(title, Owner(name)) = book println(s"titile=${title} owner=${name}")
実行結果は、以下のとおり変数「title」と「name」にインスタンスの値が設定されていることがわかります。
titile=Hello World! owner=Taro
また、match
式でcase class
を利用することができます。
先ほどの例をmatch
式で書くと以下のようになります。
book match case Book(title, Owner(name)) => println(s"titile=${title} owner=${name}")
実行結果は、以下のとおり変数「title」と「name」にインスタンスの値が設定されていることがわかります。
titile=Hello World! owner=Taro
match
式の詳細は、以下の記事を参照してください。